#ifndef __SDL_CONTROLS_H__
#define __SDL_CONTROLS_H__

#include <SDL.h>
#include <SDL_ttf.h>
#include "Widget.h"

//necesario para resolver le dependencia circular entre SDLControls y Widget
class Widget;

#define MAX_HANDLER_COUNT 25
#define MAX_ON_SCREEN_WIDGET_COUNT 100

typedef void (*SDL_CONTROLS_START_HANDLER_FUNC)();
typedef void (*SDL_EVENT_HANDLER_FUNC)(const SDL_Event& event);

/**
 * Clase encargada de administrar la interfaz gráfica
 */
class SDLControls{

private:
	int hRes;
	int vRes;
	int depth;

	bool keepLooping;

	Widget** onScreenWidgets;

	Widget* hoveredWidget;

	int onScreenWidgetCount;

	int focusIndex;

	SDL_Surface* screen;

	SDL_CONTROLS_START_HANDLER_FUNC startHandler;

	SDL_EVENT_HANDLER_FUNC globalHandlers[MAX_HANDLER_COUNT];

	static SDLControls* instance;

	SDLControls();

	/**
	 * Inicializa
	 */
	void init();

	/**
	 * Lleva a cabo las tareas que debería llevar a cabo un destructor
	 */
	void clean();

	/**
	 * Registra un "manejador" para un evento SDL
	 */
	void setGlobalHandler(const Uint8& eventType, const SDL_EVENT_HANDLER_FUNC& handler);

	/**
	 * Inicializa los "manejadores" para los eventos que son independientes de cualquier widget
	 */
	void initGlobalHandlers();

	/**
	 * Devuelve el indice correspondiente al widget si este habia sido guardado, en caso contrario devuelve -1
	 */
	int getWidgetIndex(Widget* widget);

	/**
	 * Devuelve verdadero o falso dependiendo de si el widget ya esta o no en pantalla
	 */
	bool isWidgetOnScreen(Widget* widget);

public:

	/**
 	 * Devuelve una instancia de la clase
 	 */
	static SDLControls* getInstance();

	/**
	 * Enfoca el widget recibido
	 */
	void setFocus(Widget* widget, const SDL_Event& event);

	/**
	 * Propaga el evento relacionado con el mouse capturado a los widgets mostrados
	 */
	void handleMouseMotion(Widget** widgets, const int& widgetCount, const SDL_Event& event);

	void handleMouseClick(Widget** widgets, const int& widgetCount, const SDL_Event& event);

	void handleKeyDown(const SDL_Event& event);

	/**
	 * Devuelve la resolución horizontal
	 */
	int const getHRes();

	/**
	 * Establece la resolución horizontal
 	 */
	void setHRes(const int& hRes);

	/**
	 * Devuelve la resolucion vertical
 	 */
	int const getVRes();

	/**
	 * Establece la resolucion vertical
	 */
	void setVRes(const int& vRes);

	/**
 	 * Devuelve el depth de la pantalla
	 */
	int const getDepth();

	/**
	 * Establece el depth de la pantalla
	 */
	void setDepth(const int& depth);

	/**
 	 * Activa la interfaz de usuario y da comienzo al manejo de eventos
   	 */
	void start();

	/**
	 * Atiende el evento recibido si existe un handler registrado para atender el tipo correspondiente
	 */
	void handleEvent(const SDL_Event& event);

	/**
	 * Detiene el manejo de eventos
	 */
	void stop();

	/**
	 * Registra una función que será invocada antes de entrar al loop principal
	 */
	void setStartHandler(SDL_CONTROLS_START_HANDLER_FUNC startHandler);

	/**
	 * Dibuja un widget en la pantalla
	 */
	void draw(Widget* widget, const int& x, const int& y);

	/**
	 * Dibuja un widget en el centro de la pantalla
	 */
	void center(Widget* widget);

	/**
	 * Limpia la pantalla
	 */
	void clear();

	/**
	 * Dispara acciones que deberían llevarse a cabo ante un click
	 */
	void onClick();

	/**
	 * Establece el próximo widget enfocado
	 */
	void setNextFocusedWidget(const SDL_Event& event);

	/**
	 * Devuelve el widget enfocado
	 */
	Widget* getFocusedWidget();

	/**
	 * Vuelve a obtener la pantalla
	 */
	void updateScreen();

	/**
	 * Destructor. Al ser un Singleton no hay utilidad para este metodo, todo lo que deberia hacer el destructor se hace al terminar el loop principal
	 */
	virtual ~SDLControls();
};

#endif
